package utils

import (
	"fmt"
	"dockerui/models"
	"github.com/docker/docker/client"
	"io"
	"os"
	"strings"
	"time"
)

var (
	GClient *client.Client
	GDockerChain *models.DockerChain
)

func dockerClient() (*client.Client, error){
	var (
		cli *client.Client
		err error
	)
	if cli, err = client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()); err != nil {
		fmt.Println("New client error: #{err}")
		return cli, err
	}
	return cli, err
}

func InitDockerClient() {
	var (
		err error
	)
	if GClient ,err = dockerClient(); err != nil {
		panic(err.Error())
	}
}


func FormatImageList(imagesResp []map[string]interface{}) (imageFormatResp []models.ImageFormatResp){
	/*
		对返回的镜像做处理
	*/
	var (
		created string         // 创建时间
		repository  string     // 镜像名称
		tag         string     // 处理后的镜像tag
		repoTag     string     // api返回镜像tao
		imageId     string     // 镜像id
		imageSize   string     // 镜像大小
 		formatImage = models.ImageFormatResp{}  //
	)

	for _, v := range RemoveDuplicatedElem(imagesResp) {
		repoTag = v["RepoTags"].([]string)[0]
		repository = strings.Split(repoTag, ":")[0]
		imageId = v["ID"].(string)
		tag = strings.Split(repoTag, ":")[1]
		created = time.Unix(v["Created"].(int64), 0).Format(TIMEFORMAT)
		imageSize = formatFileSize(v["Size"].(int64))
		formatImage = models.ImageFormatResp{
			Repository: repository,
			Tag: tag,
			ImageId: strings.Split(imageId, ":")[1][:12],
			Created: created,
			Size: imageSize,
		}
		imageFormatResp = append(imageFormatResp, formatImage)
	}
	return imageFormatResp
}


func FormatContainerList(containerResp []map[string]interface{}) (containerFormatResp []models.ContainerFormatResp) {
	/*
		对返回的容器做处理
	*/
	var (
		containerId  string  // 容器id
		containerImage string         // 容器所属镜像
		command string    // 容器运行entrypoint
		created string       // 创建时间
		status string        //  容器状态
		portsMap  map[string]interface{}  // Ports列表中的结构体
		exposeIp string      // 容器对外暴露Ip, 默认 0.0.0.0
		privatePort uint16     // 容器内部Port
		publicPort uint16       // 容器暴露Port
		exposeType string    // 暴露端口类型
		containerPorts string   // 容器端口 IP:PublicPort>Private/Type
		containerName  string   // 容器名称
		formatContainers models.ContainerFormatResp// 单个容器返回结果
	)

	for _, v := range containerResp {
		containerId = v["ID"].(string)[:12]
		containerImage = v["Image"].(string)
		command = v["Command"].(string)
		created = time.Unix(v["Created"].(int64), 0).Format(TIMEFORMAT)
		status = v["Status"].(string)
		// interface{} 转换参考 https://stackoverflow.com/questions/59759095/error-interface-conversion-interface-is-interface-not-mapstringinter
		portsMap = v["Ports"].([]interface{})[0].(map[string]interface{})
		exposeIp = portsMap["IP"].(string)
		privatePort = portsMap["PrivatePort"].(uint16)
		publicPort = portsMap["PublicPort"].(uint16)
		exposeType = portsMap["Type"].(string)
		containerPorts = fmt.Sprintf("%s:%d->%d/%s",exposeIp, publicPort, privatePort, exposeType)
		containerName = v["Names"].([]string)[0][1:]
		formatContainers = models.ContainerFormatResp {
			ContainerId: containerId,
			Image:       containerImage,
			Command:     command,
			Created:     created,
			Status:      status,
			Ports:       containerPorts,
			Names:       containerName,
		}
		containerFormatResp = append(containerFormatResp, formatContainers)
	}
	return containerFormatResp
}

func FormatNetworkList(networkResp []map[string]interface{}) (networkFormatResp []models.NetworksFormatResp) {
	var (
		networkId string
		networkName string
		networkAppProj string
		networkNet string  // api result map key com.docker.compose.network
		networkDriver string
		networkScop string
		formatNetworkResp models.NetworksFormatResp
	)
	for _, v := range networkResp {
		networkId = v["ID"].(string)[:12]
		if len(v["Labels"].(map[string]string)) == 0 {
			networkName = "null"
		} else {
			networkNet= v["Labels"].(map[string]string)["com.docker.compose.network"]
			networkAppProj = v["Labels"].(map[string]string)["com.docker.compose.project"]
			networkName = networkAppProj + "_" + networkNet
		}
		networkDriver = v["Driver"].(string)
		networkScop = v["Scope"].(string)
		formatNetworkResp = models.NetworksFormatResp{
			NetworkId: networkId,
			Name: networkName,
			Driver: networkDriver,
			Scope: networkScop,
		}
		networkFormatResp = append(networkFormatResp, formatNetworkResp)
	}
	return networkFormatResp
}


func CopyImage(imageReader io.ReadCloser, imageName string) error {
	var (
		wr int64
		err error
	)
	if wr, err = io.Copy(os.Stdout, imageReader); err != nil {
		fmt.Println("Copy ", imageName, " error", err)
		return err
	}
	fmt.Println(wr)
	return nil
}

func InitChain() {
	GDockerChain = &models.DockerChain{
		DownloadProcessChan: make(chan int64, 1024),
	}
}